
#include "Document.h"

const double PI = 22.0/7.0;
const double PI2 = PI/2.0;

int Document::Create( int width, int height )
{
	_width = width; _height = height;

	// Create our bitmap
	BITMAPINFO binf = {0};
	binf.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	binf.bmiHeader.biWidth = width;
	binf.bmiHeader.biHeight = -height;
	binf.bmiHeader.biPlanes = 1;
	binf.bmiHeader.biBitCount = 32;
	binf.bmiHeader.biCompression = BI_RGB;
	binf.bmiHeader.biSizeImage = 0;
	pBmpBits = NULL;
	hBmp = CreateDIBSection( NULL, &binf, DIB_RGB_COLORS, &pBmpBits, NULL, 0 );
	if (!hBmp) {
		MessageBoxW( NULL, L"Error while create DIBSection", L"Draw", MB_OK|MB_ICONERROR );
		return 0;
	}
	bufDC = CreateCompatibleDC( NULL );
	SelectObject( bufDC, hBmp );

	stride = width * 4;
	
	xmin = new int[_height];
	xmax = new int[_height];
	alpha = new UCHAR[_width*_height];
	alphas = new float[_height*_width];
	ResetAlphas();

	return 1;
}

Document::~Document(void)
{
	DeleteObject( hBmp );
	DeleteDC( bufDC );
}

void Document::BeginStroke( int x, int y ) {
	stroke = STROKE_START;
}

void Document::EndStroke() {
	if( stroke == STROKE_NONE ) return;
	stroke = STROKE_NONE;
}

/*
////p3-------------p4
////|              |
////| width1       | width2
////|              |
////x1,y1--------x2,y2
////|              |
////|              |
////|              |
////p1-------------p2
*/
void Document::DrawLine( int x1, int y1, int x2, int y2, double width1, double width2 ) {
	double w12 = width1/2.0;
	double w22 = width2/2.0;

	stroke = STROKE_MIDDLE;
	double angle = atan2( (double)(y2-y1), (double)(x2-x1) );
	double p1x = x1 + w12 * cos( angle + PI2 );
	double p1y = y1 + w12 * sin( angle + PI2 );
	
	double p2x = x2 + w22 * cos( angle + PI2 );
	double p2y = y2 + w22 * sin( angle + PI2 );
	
	double p3x = x1 + w12 * cos( angle - PI2 );
	double p3y = y1 + w12 * sin( angle - PI2 );

	double p4x = x2 + w22 * cos( angle - PI2 );
	double p4y = y2 + w22 * sin( angle - PI2 );
	
	ResetAlphas();
	DrawLine( p1x, p1y, p2x, p2y );
	DrawLine( p2x, p2y, p4x, p4y );
	DrawLine( p4x, p4y, p3x, p3y );
	DrawLine( p3x, p3y, p1x, p1y );
	RenderAlphas();
}

// Xiaolin Wu
void Document::DrawLine( double x0, double y0, double x1, double y1 ) {
	// dont draw horizontal edge
	if( y1==y0 ) return;

	bool le/*left edge*/ = y1-y0>0 ? true : false;
	bool te/*top edge*/ = x1-x0<0 ? true :false;

	bool steep = abs( y1 - y0 ) > abs( x1 - x0 );

	if( steep ) {
		swap( x0, y0 );
		swap( x1, y1 );
	}
	if( x0 > x1 ) {
		swap( x0, x1 );
		swap( y0, y1 );
	}
	double dx = x1 - x0;
	double dy = y1 - y0;

	double gradient = dy / dx;

	// handle first endpoint
	double xend = round( x0 );
	double yend = y0 + gradient * ( xend - x0 );
	double xgap = rfpart( x0 + 0.5 );
	int xpxl1 = xend; // used in main loop
	int ypxl1 = ipart( yend );

	if( steep ) {
		if( le )
			PutAlpha( ypxl1, xpxl1, rfpart( yend ) * xgap );
		else
			PutAlpha( ypxl1+1, xpxl1, fpart( yend ) * xgap );
	} else {
		if( te )
			PutAlpha( xpxl1, ypxl1, rfpart( yend ) * xgap );
		else
			PutAlpha( xpxl1, ypxl1+1, rfpart( yend ) * xgap );
	}
	double intery = yend + gradient; // first y-intersection for the main loop

	// handle second endpoint
	
	xend = round( x1 );
	yend = y1 + gradient * ( xend - x1 );
	xgap = rfpart( x1 + 0.5 );
	int xpxl2 = xend; // used in main loop
	int ypxl2 = ipart( yend );

	if( steep ) {
		if( le )
			PutAlpha( ypxl2, xpxl2, rfpart( yend ) * xgap );
		else
			PutAlpha( ypxl2+1, xpxl2, fpart( yend ) * xgap );
	} else {
		if( te )
			PutAlpha( xpxl2, ypxl2, rfpart( yend ) * xgap );
		else
			PutAlpha( xpxl2, ypxl2+1, rfpart( yend ) * xgap );
	}

	// main loop
	for( int x=xpxl1+1; x<xpxl2; x++ ) {
		if( steep ) {
			if( le )
				PutAlpha( ipart(intery), x, rfpart(intery));
			else
				PutAlpha( ipart(intery)+1, x, fpart(intery));
		} else {
			if( te )
				PutAlpha( x, ipart(intery), rfpart(intery));
			else
				PutAlpha( x, ipart(intery)+1, fpart(intery));
		}
		intery += gradient;
	}
}

const int Document::gamma[] = 
{
    0,  0,  1,  1,  2,  2,  3,  4,  4,  5,  5,  6,  7,  7,  8,  8,
    9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 16, 16, 17, 18, 18,
    19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28,
    29, 29, 30, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37, 38,
    39, 39, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 49,
    49, 50, 51, 51, 52, 53, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60,
    60, 61, 62, 62, 63, 64, 65, 65, 66, 67, 68, 68, 69, 70, 71, 71,
    72, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 82, 83, 83, 84,
    85, 86, 87, 88, 89, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
    100,101,101,102,103,104,105,106,107,108,109,110,111,112,114,115,
    116,117,118,119,120,121,122,123,124,126,127,128,129,130,131,132,
    134,135,136,137,139,140,141,142,144,145,146,147,149,150,151,153,
    154,155,157,158,159,161,162,164,165,166,168,169,171,172,174,175,
    177,178,180,181,183,184,186,188,189,191,192,194,195,197,199,200,
    202,204,205,207,209,210,212,214,215,217,219,220,222,224,225,227,
    229,230,232,234,236,237,239,241,242,244,246,248,249,251,253,255
};